package com.fingard.dsp.bank.directbank.bocom13;

import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.dbobj.receipt.ReceiptData;
import com.fingard.dsp.bank.dbobj.receipt.ReceiptDataHelper;
import com.fingard.dsp.bank.directbank.DirectHelper;
import com.fingard.dsp.bank.directbank.bankInterface.IAcceptNotice;
import com.fingard.dsp.bank.directbank.bocom13.util.JavaMD5;
import com.fingard.dsp.bank.directbank.bocom13.util.Mac;
import com.fingard.dsp.bank.helpers.FileType;
import com.fingard.dsp.bank.syncfile.FileItem;
import com.fingard.dsp.task.command.SyncReceipt;
import com.fingard.generalobj.NoticeReq;
import com.fingard.generalobj.NoticeResp;
import com.fingard.io.FileHelper;
import com.fingard.net.listener.SocketReceiver;
import com.fingard.text.StringHelper;
import com.fingard.util.GZipHelper;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Date;

/**
 * 交行资金清算平台(BOCOM13)异步通知
 */
public class BOCOM13AcceptNotice extends BOCOM13Base implements IAcceptNotice {
    public int zipFileSize = 0;
    public int zipByteCount = 0;
    public String zipFileName = "";
    public String zipFileMD5 = "";
    public FileOutputStream localFileStream = null;

    @Override
    public NoticeResp dealNotice(NoticeReq pNtReq) throws Exception {
        NoticeResp resp = new NoticeResp();
        byte[] bytesBkRet = pNtReq.reqBytes;
        String tmpStrRet = "";
        String Threehundred = "%-300s";

        String Twenty = "%-20s";
        String tmpErrCode = "000001";
        String tmpStrReq = new String(bytesBkRet, getCharset());
        WriteBankLogLn("异步通知请求报文:\r\n" + tmpStrReq);
        if (tmpStrReq.contains("<?xml")) {
            // 联机交易报文交互
            tmpStrReq = tmpStrReq.substring(tmpStrReq.indexOf('<'));
            StringBuilder tmpSbMsg = new StringBuilder();
            XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrReq, tmpSbMsg);

            String transCode = tmpBkReader.getFirstText("/Req/Head/TrCode");
            WriteBankLogLn2("异步通知联机交易代码:" + transCode);
            if ("B60911".equalsIgnoreCase(transCode) || "I60911".equalsIgnoreCase(transCode)) {
                // 文件确认
                BOCOM13Header tmpBankHeader = new BOCOM13Header();
                tmpBankHeader.transCode = "B60911";
                tmpBankHeader.reqSeqID = getQryTransID();
                XmlTextWriter xmlWriter = new XmlTextWriter();
                xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"" + getCharset() + "\"?>");
                xmlWriter.writeStartElement("Rsp");
                xmlWriter.writeStartElement("Head");
                if (tmpBkReader != null) {
                    xmlWriter.writeElementString("MsgType", "N");
                    xmlWriter.writeElementString("ErrCode", "000000");
                    xmlWriter.writeElementString("ErrMsg", "成功");
                } else {
                    xmlWriter.writeElementString("MsgType", "E");
                    xmlWriter.writeElementString("ErrCode", tmpErrCode);
                    xmlWriter.writeElementString("ErrMsg", tmpSbMsg.toString());
                }
                xmlWriter.writeStartElement("Sender");/* 交易请求方 */
                xmlWriter.writeElementString("OrgType", tmpBkReader.getFirstText("/Req/Head/Sender/OrgType"));/* 机构类型 */
                xmlWriter.writeElementString("OrgId", tmpBkReader.getFirstText("/Req/Head/Sender/OrgId"));/* 机构ID */
                xmlWriter.writeElementString("BrchId", tmpBkReader.getFirstText("/Req/Head/Sender/BrchId"));/* 交易区域(保险分公司编码) */
                xmlWriter.writeElementString("SubBrchId", tmpBkReader.getFirstText("/Req/Head/Sender/SubBrchId"));/* 交易机构 */
                xmlWriter.writeElementString("BusDate", tmpBkReader.getFirstText("/Req/Head/Sender/BusDate"));/* 业务日期 */
                xmlWriter.writeElementString("SeqNo", tmpBkReader.getFirstText("/Req/Head/Sender/SeqNo"));/* 交易流水号 */
                xmlWriter.writeEndElement();
                xmlWriter.writeStartElement("Recver");/* 交易应答方 */
                xmlWriter.writeElementString("OrgType", tmpBkReader.getFirstText("/Req/Head/Recver/OrgType"));/* 机构类型 */
                xmlWriter.writeElementString("OrgId", tmpBkReader.getFirstText("/Req/Head/Recver/OrgId"));/* 机构ID(3012900:交通银行) */
                xmlWriter.writeElementString("BrchId", tmpBkReader.getFirstText("/Req/Head/Recver/BrchId"));/* 交易区域(银行分行代码) */
                xmlWriter.writeElementString("SubBrchId", tmpBkReader.getFirstText("/Req/Head/Recver/SubBrchId"));/* 交易机构(银行机构代码) */

                Date date = new Date();
                xmlWriter.writeElementString("BusDate", Format.Date8Format.format(date));/* 业务日期 */
                xmlWriter.writeElementString("SeqNo", Format.DateTime17SSSFormat.format(date));/* 交易流水号 */
                xmlWriter.writeElementString("TrDate", Format.Date8Format.format(date));/* 交易日期 */
                xmlWriter.writeElementString("TrTime", Format.Time6Format.format(date));/* 交易时间 */
                xmlWriter.writeEndElement();
                xmlWriter.writeEndElement();
                xmlWriter.writeStartElement("Body");/* 交易应答方 */
                xmlWriter.writeElementString("BatNo", tmpBkReader.getFirstText("/Req/Body/BatNo"));/* 批次号 */
                xmlWriter.writeEndDocument();
                tmpStrRet = xmlWriter.toXmlString();

                String tmpReqFileName = tmpBkReader.getFirstText("/Req/Body/FileName");
                File tmpReqFile = new File(getNotifyDataDirectory() + File.separator + tmpReqFileName);
                String tmpGZipFilePath = tmpReqFile.getPath();
                WriteBankLogLn2("解压前银行返回批次请求文件保存本机路径:\r\n" + tmpGZipFilePath);

                if (tmpReqFile.exists()) {
                    if (tmpReqFile.getName().endsWith(".pdf")) {
                        // 业务凭证文件
                        String receiptNo = DirectHelper.getReqSeqIDMapping(tmpReqFileName);
                        ReceiptData eachData = new ReceiptData();
                        eachData.setBusDate(date);
                        eachData.istNbr = receiptNo+eachData.busDate;
                        eachData.localFile = tmpGZipFilePath;
                        eachData.srcFile = "";
                        eachData.busRef = receiptNo;
                        eachData.receiptNo = receiptNo;
                        eachData.bank = "301";
                        eachData.srcSys = "BOCOM13";
                        eachData.ownAct = getBankConfig().getMapValueByKey("corpNoMapping", tmpBkReader.getFirstText("/Req/Head/Recver/OrgId"));
                        eachData.downState = "2";
                        eachData.downTime = new Date();
                        eachData.moneyWay = "1";
                        ReceiptDataHelper receiptHelper = new ReceiptDataHelper("", date);
                        int inRe = receiptHelper.insertIfNotExistByReceiptNo(eachData, true);
                        WriteBankLogLn(eachData.receiptNo+"写入数据库，影响行数："+inRe);
                        SyncReceipt.resetDelayCounter();
                    } else {
                        WriteBankLogLn2("开始进行解压...");
                        GZipHelper.doUncompressFile(tmpGZipFilePath);
                        WriteBankLogLn2("解压完成.");

                        String tmpLocalFilePath = tmpGZipFilePath.replace(".gz", "");
                        WriteBankLogLn("解压后待处理结果文件:" + tmpLocalFilePath);

                        File tmpLocalFile = new File(tmpLocalFilePath);
                        if (tmpLocalFile.exists()) {
                            String[] tmpRspFileArray = tmpReqFileName.split("_");
                            if (tmpRspFileArray != null && tmpRspFileArray.length > 0) {
                                byte tmpByteSp = 0x0F;// 域分隔符

                                byte[] tmpBytesRet = FileHelper.readFileBytes(tmpLocalFilePath);
                                byte[] tmpBytesResp = new byte[tmpBytesRet.length];
                                for (int i = 0; i < tmpBytesRet.length; i++) {
                                    if (tmpByteSp == tmpBytesRet[i]) {
                                        tmpBytesResp[i] = ',';
                                    } else {
                                        tmpBytesResp[i] = tmpBytesRet[i];
                                    }
                                }
                                String[] tmpHeaderArray = new String(tmpBytesResp, getCharset()).split("\n")[0].split(",");

                                String transDate = "";
                                String transFileType = "";
                                if (tmpRspFileArray.length >= 6) {
                                    transDate = tmpRspFileArray[2];
                                    int index = tmpRspFileArray[5].indexOf('.');
                                    transFileType = tmpRspFileArray[5].substring(0, index);
                                }
                                WriteBankLogLn2("文件类型:" + transFileType);
                                String tmpReusltFilePath = "";
                                if ("I11".equalsIgnoreCase(transFileType) || "I12".equalsIgnoreCase(transFileType)) {
                                    // 批量代收付文件
                                    tmpReusltFilePath = createNotifyDataDirectory(transDate) + File.separator + tmpHeaderArray[16].trim() + ".txt";
                                    WriteBankLogLn2("批量代收付结果文件保存本机路径:" + tmpReusltFilePath);
                                    FileHelper.writeFile(tmpReusltFilePath, new String(tmpBytesRet, getCharset()), getCharset());
                                    WriteBankLogLn("批量代收付结果文件内容:\r\n" + FileHelper.readFileText(tmpReusltFilePath, getCharset()));
                                } else if ("I41".equalsIgnoreCase(transFileType) || "I42".equalsIgnoreCase(transFileType)) {
                                    // 批量代收付对账单文件
                                    tmpReusltFilePath = createNotifyDataDirectory(transDate) + File.separator + tmpRspFileArray[3].trim() + "_" + transFileType + ".txt";
                                    WriteBankLogLn2("批量代收付对账单文件保存本机路径:" + tmpReusltFilePath);
                                    FileHelper.writeFile(tmpReusltFilePath, new String(tmpBytesRet, getCharset()), getCharset());
                                    WriteBankLogLn("批量代收付对账单文件内容:\r\n" + FileHelper.readFileText(tmpReusltFilePath, getCharset()));
                                } else if ("I13".equalsIgnoreCase(transFileType)) {
                                    tmpReusltFilePath = createNotifyDirectory() + File.separator + tmpHeaderArray[10].trim() + ".txt";
                                    WriteBankLogLn2("批量签约授权结果文件保存本机路径:" + tmpReusltFilePath);
                                    FileHelper.writeFile(tmpReusltFilePath, new String(tmpBytesRet, getCharset()), getCharset());
                                    WriteBankLogLn("批量签约授权结果文件内容:\r\n" + FileHelper.readFileText(tmpReusltFilePath, getCharset()));
                                } else if ("I14".equalsIgnoreCase(transFileType)) {
                                    tmpReusltFilePath = createNotifyDirectory() + File.separator + "qry_authInfo_" + tmpHeaderArray[7].trim() + ".txt";
                                    WriteBankLogLn2("银保通代销保单签约结果文件保存本机路径:" + tmpReusltFilePath);
                                    FileHelper.writeFile(tmpReusltFilePath, new String(tmpBytesRet, getCharset()), getCharset());
                                    WriteBankLogLn("银保通代销保单签约结果文件内容:\r\n" + FileHelper.readFileText(tmpReusltFilePath, getCharset()));
                                }
                                if (StringHelper.hasAnyChar(tmpReusltFilePath)) {
                                    FileItem fileItem = new FileItem();
                                    fileItem.localFilePath = tmpReusltFilePath;
                                    fileItem.relativePath = this.getRelativeDataDirPath(tmpReusltFilePath);
                                    fileItem.fileType = FileType.dataFile;
                                    String syncRet = FGBiz.clusterCenter.syncFile(fileItem);
                                    if (StringHelper.hasAnyChar(syncRet)) {
                                        WriteBankLogLn(syncRet);
                                    }
                                }
                            }
                        } else {
                            WriteBankLogLn2("解压后待处理结果文件不存在!");
                        }
                    }
                } else {
                    WriteBankLogLn2("解压前银行返回批次请求文件不存在!");
                }
            }
        } else {
            // 文件传输交互
            String transCode = new String(bytesBkRet, 24, 6);
            WriteBankLogLn("银行通知交易码:" + transCode);

            int askBlockSeq = 0;

            if ("B60901".equals(transCode) || "I60901".equals(transCode)) {
                WriteBankLogLn("接收到的请求数据为【报文1】");
                String bkTransSeq = new String(bytesBkRet, 85, 20);
                WriteBankLogLn("交易流水号:" + bkTransSeq);

                zipFileName = new String(bytesBkRet, 119, 128).trim();
                WriteBankLogLn("压缩文件名称:" + zipFileName);

                zipFileSize = Integer.parseInt(new String(bytesBkRet, 247, 12));
                WriteBankLogLn("文件大小:" + zipFileSize);

                zipByteCount = Integer.parseInt(new String(bytesBkRet, 259, 8));
                WriteBankLogLn("数据包大小：" + zipByteCount);

                zipFileMD5 = new String(bytesBkRet, 267, 200).trim();
                WriteBankLogLn("文件MD5校验值:" + zipFileMD5);

                WriteBankLogLn("初始文件块序号:" + askBlockSeq);
                tmpStrRet = "G000000";
            } else if ("B60902".equals(transCode) || "I60902".equals(transCode)) {
                WriteBankLogLn("接收到的请求数据为【报文3】");
                int tmpBkSeq = Integer.parseInt(new String(bytesBkRet, 30, 6));
                WriteBankLogLn("当前【报文3】中块序号:" + tmpBkSeq);
                if (askBlockSeq == tmpBkSeq) {
                    String localFileName = createNotifyDataDirectory() + File.separator + zipFileName;
                    WriteBankLogLn("保存到本地文件名:" + localFileName);
                    if (new File(localFileName).exists()) {
                        WriteBankLogLn("本地文件已存在...");
                    } else {
                        WriteBankLogLn("本地文件不存在...");
                    }
                    localFileStream = new FileOutputStream(new File(localFileName));
                    byte[] tmpBytes = new byte[bytesBkRet.length - 36];
                    System.arraycopy(bytesBkRet, 36, tmpBytes, 0, bytesBkRet.length - 36);
                    localFileStream.write(tmpBytes);
                    localFileStream.close();
                    FileItem fileItem = new FileItem();
                    fileItem.localFilePath = localFileName;
                    fileItem.relativePath = this.getRelativeDataDirPath(localFileName);
                    fileItem.fileType = FileType.dataFile;
                    String syncRet = FGBiz.clusterCenter.syncFile(fileItem);
                    if (StringHelper.hasAnyChar(syncRet)) {
                        WriteBankLogLn(syncRet);
                    }
                    int fileByteWriteCount = bytesBkRet.length - 36;
                    WriteBankLogLn("当前数据包字节大小:" + fileByteWriteCount);
                    if (fileByteWriteCount >= zipFileSize) {
                        WriteBankLogLn("实际压缩包文件byte总长度:|" + fileByteWriteCount + "|");
                        WriteBankLogLn("报文中压缩包文件byte总长度:|" + zipFileSize + "|");
                        if (fileByteWriteCount != zipFileSize) {
                            String tmpPck5Tail = Format.Date8Format.format(new Date()) + String.format("%20s", Format.DateTime17Format.format(new Date())).replace(" ", "0");
                            tmpStrRet = "E000009" + String.format(Threehundred, "实际写入文件字节数" + fileByteWriteCount + "不等于预期文件字节数" + zipFileSize) + tmpPck5Tail;
                        } else {
                            String tmpGZMD5 = JavaMD5.generateFileMD5(localFileName);
                            WriteBankLogLn("当前接收文件实际计算的MAC:|" + tmpGZMD5 + "|");
                            WriteBankLogLn("请求报文1中文件的MAC:|" + zipFileMD5 + "|");
                            if (zipFileMD5.equals(tmpGZMD5)) {
                                StringBuilder tmpSbPck1 = new StringBuilder();
                                tmpSbPck1.append("N");
                                tmpSbPck1.append("000000");
                                tmpSbPck1.append(String.format(Threehundred, "文件传输成功"));
                                tmpSbPck1.append(Format.Date8Format.format(new Date()));
                                tmpSbPck1.append(String.format(Twenty, Format.DateTime17Format.format(new Date())).replace(" ", "0"));
                                tmpSbPck1.append(String.format("%-1500s", ""));
                                tmpStrRet = tmpSbPck1.toString();
                            } else {
                                StringBuilder tmpSbPck1 = new StringBuilder();
                                tmpSbPck1.append("E");
                                tmpSbPck1.append("000009");
                                tmpSbPck1.append(String.format(Threehundred, "MD5校验失败，本地产生的MD5为:" + tmpGZMD5));
                                tmpSbPck1.append(Format.Date8Format.format(new Date()));
                                tmpSbPck1.append(String.format(Twenty, Format.DateTime17Format.format(new Date())).replace(" ", "0"));
                                tmpStrRet = tmpSbPck1.toString();
                            }
                        }
                        //数据包总数 = ( 文件大小 + ( 数据包大小 - 1 ) ) / 数据包大小  如果不是最后一个数据包且数据包长度不足够2M，就重传
                    } else if (askBlockSeq != (((zipFileSize + (zipByteCount - 1)) / zipByteCount) - 1) && fileByteWriteCount < zipByteCount) {
                        WriteBankLogLn("需要重传,重传文件块序号:" + askBlockSeq);
                        tmpStrRet = "R" + String.format("%06d", askBlockSeq);
                    } else {
                        askBlockSeq = askBlockSeq + 1;
                        WriteBankLogLn("当前文件块序号:" + askBlockSeq);
                        tmpStrRet = "G" + String.format("%06d", askBlockSeq);
                    }
                } else {
                    StringBuilder tmpSbPck1 = new StringBuilder();
                    tmpSbPck1.append("E");
                    tmpSbPck1.append(tmpErrCode);
                    tmpSbPck1.append(String.format(Threehundred, "请求数据包：" + askBlockSeq + "，但银行返回" + tmpBkSeq));
                    tmpSbPck1.append(Format.Date8Format.format(new Date()));
                    tmpSbPck1.append(String.format(Twenty, Format.DateTime17Format.format(new Date())).replace(" ", "0"));
                    tmpSbPck1.append(String.format("%1500s", ""));
                    tmpStrRet = tmpSbPck1.toString();
                }
            } else {
                StringBuilder tmpSbPck1 = new StringBuilder();
                tmpSbPck1.append("E");
                tmpSbPck1.append(tmpErrCode);
                tmpSbPck1.append("E000001" + String.format(Threehundred, "不支持的交易码：" + transCode));
                tmpSbPck1.append(Format.Date8Format.format(new Date()));
                tmpSbPck1.append(String.format(Twenty, Format.DateTime17Format.format(new Date())).replace(" ", "0"));
                tmpSbPck1.append(String.format("%-1500s", ""));
                tmpStrRet = new String(bytesBkRet);
            }
        }

        String macKey = getBankConfig().getValueAsString("macKey");
        WriteBankLogLn("通讯密钥内容:" + macKey);
        if (StringHelper.isNullOrEmpty(macKey)) {
            tmpStrRet = "通讯密钥内容为空,请检查配置文件config.xml中'macKey'配置信息.";
        } else {
            String msgMac = Mac.generateMac(macKey.getBytes(getCharset()), tmpStrRet.getBytes(getCharset()));
            byte[] msgMacBytes = msgMac.getBytes(getCharset());
            if (msgMacBytes.length != 16) {

                tmpStrRet = "生成的MAC值:[" + msgMac + "]长度非16字节";
            } else {
                String tmpReqMsgHeader = String.format("%08d", (msgMac + tmpStrRet).getBytes(getCharset()).length) + msgMac;
                tmpStrRet = tmpReqMsgHeader + tmpStrRet;
            }
        }

        WriteBankLogLn("异步通知响应报文:\r\n" + tmpStrRet);
        resp.respBytes = tmpStrRet.getBytes(pNtReq.reqCharset);
        return resp;
    }

    @Override
    public void getContentLength(SocketReceiver p_receiver) throws Exception {
        if (p_receiver.contentLength == -1 && p_receiver.readedLength >= 24) {
            p_receiver.contentLength = Integer.parseInt(new String(p_receiver.reqBytes, 0, 8, getCharset()).trim()) - 16;
            p_receiver.contentStartIndex = 24;

        }
    }
}